package me.magicall.test.backup;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import me.magicall.util.ArrayUtil;
import me.magicall.util.kit.Kits;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

//@Component
public class ModelEnumHolder implements ApplicationContextAware {

	private static final String resourcePattern = "**/*.class";

	private final Map<String, Class<? extends Enum<?>>> map = new HashMap<String, Class<? extends Enum<?>>>();

	private String[] basePackages;

	public Class<? extends Enum<?>> getEnumClass(final String enumName) {
		Class<? extends Enum<?>> c = map.get(resolveName(enumName));
		if (c == null) {
			c = map.get(toShortName(enumName));
		}
		return c;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
		final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(applicationContext);
		final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
		if (!ArrayUtil.isEmpty(basePackages)) {
			for (final String basePackage : basePackages) {
				try {
					final String packageSearchPath = "classpath*:" + resolveBasePackage(basePackage) + "/" + resourcePattern;
					final Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
					for (final Resource resource : resources) {//resource ref to a .class file
						if (resource.isReadable()) {
							try {
								final MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
								if (isCandidateComponent(metadataReader)) {
									try {
										final String beanClassName = metadataReader.getClassMetadata().getClassName();
										final Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) Class.forName(beanClassName);
										map.put(resolveName(beanClassName), enumClass);//full name
										map.put(toShortName(beanClassName), enumClass);//short name
									} catch (final ClassNotFoundException e) {
										e.printStackTrace();
									}
								}
							} catch (final Throwable ex) {
								throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);
							}
						}
					}
				} catch (final IOException ex) {
					throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
				}
			}
		}
	}

	/**
	 * @param beanClassName
	 * @return
	 */
	private String resolveName(final String beanClassName) {
		return beanClassName.toLowerCase();
	}

	private String toShortName(final String beanClassName) {
		return ClassUtils.getShortName(beanClassName).toLowerCase();
	}

	private String resolveBasePackage(final String basePackage) {
		return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
	}

	private boolean isCandidateComponent(final MetadataReader metadataReader) {
		return metadataReader.getClassMetadata().getSuperClassName().equals("java.lang.Enum");
	}

}
